package com.jwcao.common.cast.operation;

import com.jwcao.common.cast.context.KeyFactory;
import com.jwcao.common.cast.operation.callback.FromCallBackOperation;
import com.jwcao.common.cast.operation.callback.ToCallBackOperation;
import com.jwcao.common.cast.operation.injection.FieldInjectionOperation;
import com.jwcao.common.cast.operation.injection.InjectionOperation;
import com.jwcao.common.cast.operation.instance.InstanceOperation;
import com.jwcao.common.scan.object.ScanClass;
import java.util.List;
import lombok.Getter;

/**
 * name: CastFlow description: TODO
 *
 * @author caojingwei date: 2023/3/23 17:48
 */
@Getter
public class CastFlow {

    private final String id;

    private final String key;
    private final String keyWithoutId;

    private final ScanClass sourceClass;
    private final ScanClass targetClass;

    private final InstanceOperation instanceOperation;
    private final List<InjectionOperation> injectionOperationList;
    private final FromCallBackOperation fromCallBackOperation;
    private final ToCallBackOperation toCallBackOperation;

    public CastFlow(String id, ScanClass sourceClass, ScanClass targetClass,
        InstanceOperation instanceOperation,
        List<InjectionOperation> injectionOperationList,
        FromCallBackOperation fromCallBackOperation,
        ToCallBackOperation toCallBackOperation) {
        this.id = id;
        this.key = KeyFactory.get(sourceClass.getClazz(), targetClass.getClazz(), id);
        this.keyWithoutId = KeyFactory.getWithoutId(sourceClass.getClazz(), targetClass.getClazz());
        this.sourceClass = sourceClass;
        this.targetClass = targetClass;
        this.instanceOperation = instanceOperation;
        this.injectionOperationList = injectionOperationList;
        this.fromCallBackOperation = fromCallBackOperation;
        this.toCallBackOperation = toCallBackOperation;
    }

    public Object execute(Object sourceObject) {
        Object targetObject = instanceOperation.execute(sourceObject);
        injectionOperationList.forEach(i -> i.execute(sourceObject, targetObject));
        if (fromCallBackOperation != null) {
            fromCallBackOperation.execute(targetObject);
        }
        if (toCallBackOperation != null) {
            toCallBackOperation.execute(sourceObject, targetObject);
        }
        return targetObject;
    }

    public void flush() {
        injectionOperationList.stream().filter(o -> o instanceof FieldInjectionOperation)
            .forEach(o -> ((FieldInjectionOperation) o).flush());
    }
}
